ひとりNavigation API Advent Calendar 16日目
https://gyazo.com/44ebcab732b90fd171ca2521ed77c89e
これはひとりNavigation API Advent Calendarの16日目です。
昨日の続きでVue RouterのNavigation API対応を見ようと思ったけど対応もまだ途中なので方向転換します
@uhyo_: 🎁FUNSTACK Router 0.0.1リリース🎁
Navigation APIが最近熱いので、じゃあNavigation APIを使ってルーターライブラリを作るよねということで作ったやつです。
PoC的な立ち位置ではあるけど要チェック(?)
https://github.com/uhyo/funstack-router/releases/tag/0.0.1
uhyoさんが今日Navigation APIでのルーターライブラリを公開していたのでこれを見ていきます
https://github.com/uhyo/funstack-router/blob/master/docs/FUNSTACK_Router_Hero_small.png?raw=true
FUNSTACK Router
FUNSTACK Router - Documentation
サイトも用意されてある
Vite+Reactのサイトで内部のルーティングでFUNSTACK Routerを使ってる
地産地消だ
2025-12-16にv0.0.1としてリリース
PoC段階なので本番環境での使用はまだ推奨されていない
code:js
import { Router, route, Outlet } from "@funstack/router";
// Define your page components
function Home() {
return <h1>Welcome Home</h1>;
}
function About() {
return <h1>About Us</h1>;
}
function Layout() {
return (
<div>
<nav>
<a href="/">Home</a>
<a href="/about">About</a>
</nav>
<Outlet />
</div>
);
}
// Define your routes
const routes = [
route({
path: "/",
component: Layout,
children: [
route({ path: "/", component: Home }),
route({ path: "/about", component: About }),
],
}),
];
// Render the router
function App() {
return <Router routes={routes} />;
}
見た目としてはReact Routerのそれと変わらなそう
Outletがどういう仕組みなのだろうか
子ルートのコンポーネントをレンダリングする仕組み部分らしい
ネストされたレイアウトのために親ルートで使用
これはReact Routerでもある機構だった
https://reactrouter.com/start/declarative/routing#nested-routes
では内部実装を見ていこう
https://github.com/uhyo/funstack-router/tree/master/packages/router
https://github.com/uhyo/funstack-router/blob/84f152ff484a9264c4eb473f7e5a530ec52acf7f/packages/router/src/navigation-api.d.ts
ここにNavigation APIの型定義がある
ひとりNavigation API Advent Calendar 09日目とでTypeScript側との比較できる
URLPatternも含まれている
全体のアーキテクチャ
https://github.com/uhyo/funstack-router/blob/84f152ff484a9264c4eb473f7e5a530ec52acf7f/docs/architecture.md
RouterAdapter インターフェースにて以下アダプターを吸収
NavigationAPIAdapter
StaticAdapter
For unsupported browsers, use the fallback="static" option on the Router component, which renders matched routes without SPA navigation capabilities (links cause full page loads).
<Router>のfallback="static"オプションでNavigation API非対応ブラウザでも使える(SPAの動作にはならない)
サイト自体もfallback="static"にしていた
https://github.com/uhyo/funstack-router/blob/84f152ff484a9264c4eb473f7e5a530ec52acf7f/packages/docs/src/App.tsx#L34
最低限の静的レンダリングだけ提供するオプトインのfallback
SPA ナビゲーションは提供しない
ルーティングと初期レンダリングだけ行う
MPAのようにページ遷移(フルリロード)する
History APIベースの代替実装は行わない
デフォルトは「fallback なし」なので後方互換性を維持
Rendering Strategies | React Router
Static Pre-renderingをするには設定ファイルを弄る必要あり
今後の検討事項
Pending UI:ローディングインジケーター
View Transitions API
スクロールの復元:自動スクロール位置管理
Prefetch:リンクのホバー時のルート事前読み込み
データローディング設計
https://github.com/uhyo/funstack-router/blob/84f152ff484a9264c4eb473f7e5a530ec52acf7f/docs/DATA_LOADER_ARCHITECTURE.md
初回ロード:Router 初回レンダー時に loader 実行
ナビゲーション時:navigation.intercept() 内で即実行
code:js
navigation.addEventListener("navigate", (event) => {
event.intercept({
handler: async () => {
matchRoutes() for destination URL
↓
Execute loaders, write to cache ← Starts immediately!
}
})
});
loader結果のキャッシュ戦略
navigation entry key + route path をキーにキャッシュ
履歴移動(戻る/進む)では同じ entry key が使われるため、即座にキャッシュヒット
ページリロードでキャッシュはクリア
code:cache
Navigate to /users/1 → entry key "abc" → loader runs, cached
Navigate to /users/2 → entry key "def" → loader runs, cached
Press Back → entry key "abc" → cache HIT, no loader execution
Press Forward → entry key "def" → cache HIT, no loader execution
React Routerとの比較
React Router:loaderの結果をresolved値として提供
FUNSTACK Router:Promise のまま渡す
コンポーネントがuse()で制御できる
code:tsx
function UserDetail({ data, params }: { data: Promise<User>; params: { userId: string } }) {
const user = use(data); // Component chooses when to suspend
return <div>{user.name} (ID: {params.userId})</div>;
}
https://github.com/uhyo/funstack-router/blob/84f152ff484a9264c4eb473f7e5a530ec52acf7f/packages/router/src/core/NavigationAPIAdapter.ts
Navigation APIを利用したルーター内部の遷移処理を統一的に扱うためのアダプタークラス
主な機能
addEventListener / removeEventListener
Navigation API の navigate イベントを購読し、ルーターに通知する仕組みを提供
updateCurrentEntry
現在のエントリの state を更新する
navigate
History APIのpushState / replaceState のような履歴操作を抽象化し、Navigation API 経由で遷移を実行
canGoBack / canGoForward
履歴の前後移動が可能かどうかを判定
goBack / goForward
実際にページ前・後へ移動する操作
React Routerの構成は基本的に倣ってるけどデータロード機構・キャッシュ戦略、静的レンダリングは独自の設計になっていて差別化されていた
まだPoC段階とのことなので今後に期待が高まるルーターライブラリですyamanoku.icon
FUNSTACK Router: Navigation APIを用いたルーターライブラリ
uhyoさんが記事出してた
ひとりNavigation API Advent Calendarの紹介ありがとうございます